import 'package:bigegg/common/log/xmm_logcat.dart';
import 'package:bigegg/global/xmm_app_const.dart';
import 'package:bigegg/utils/xmm_event_bus.dart';
import 'package:rongcloud_im_wrapper_plugin/rongcloud_im_wrapper_plugin.dart';

class XmmImManager {
  static XmmImManager get instance => _instance ??= XmmImManager._internal();
  static XmmImManager? _instance;
  static int timeout = 30;

  XmmImManager._internal();

  RCIMIWEngine? engine;

  Future<void> init(String appKey) async {
    RCIMIWEngineOptions options = RCIMIWEngineOptions.create();
    engine = await RCIMIWEngine.create(appKey, options);
    engine?.onConnectionStatusChanged = (RCIMIWConnectionStatus? status) {
      XmmXLogcat.d("Im connection status changed: $status");
    };
    engine?.onMessageReceived =
        (RCIMIWMessage? message, int? left, bool? offline, bool? hasPackage) {
      XmmXLogcat.d("Im received message ${message?.toJson()}");
      XmmEventBus.instance.emit(XmmAppConst.eventReceivedMessageKey, message);
    };
  }

  Future<int> connect(String token) async {
    RCIMIWConnectCallback? callback = RCIMIWConnectCallback(
      onConnected: (int? code, String? userId) {
        XmmXLogcat.d("Im onConnected: code:$code, userId:$userId");
        return code;
      },
      onDatabaseOpened: (int? code) {
        XmmXLogcat.d("Im onDatabaseOpened: code:$code");
      },
    );
    int? ret = await engine?.connect(token, timeout, callback: callback);
    XmmXLogcat.d("Im connect result $ret");
    return ret ?? -1;
  }

  Future<int> sendMessage(RCIMIWMessage? message,
      {RCIMIWSendMessageCallback? callback}) async {
    if (message == null) {
      return -1;
    }
    RCIMIWSendMessageCallback? internalCallback = RCIMIWSendMessageCallback(
      onMessageSaved: callback?.onMessageSaved,
      onMessageSent: (int? code, RCIMIWMessage? message) {
        XmmEventBus.instance.emit(XmmAppConst.eventSendMessageKey, message);
        callback?.onMessageSent.call(code, message);
      },
    );
    var result = await XmmImManager.instance.engine
        ?.sendMessage(message, callback: internalCallback);
    return result ?? -1;
  }

  Future<int> sendMediaMessage(RCIMIWMediaMessage? message,
      {RCIMIWSendMediaMessageListener? callback}) async {
    if (message == null) {
      return -1;
    }
    RCIMIWSendMediaMessageListener? internalCallback = RCIMIWSendMediaMessageListener(
        onMediaMessageSaved: (RCIMIWMediaMessage? message) {
          XmmEventBus.instance.emit(XmmAppConst.eventSendMessageKey, message);
          callback?.onMediaMessageSaved?.call(message);
        },
        onMediaMessageSending: callback?.onMediaMessageSending,
        onSendingMediaMessageCanceled: callback?.onSendingMediaMessageCanceled,
        onMediaMessageSent: (int? code, RCIMIWMediaMessage? message) {
          XmmEventBus.instance.emit(XmmAppConst.eventSyncMessageStatusKey, message);
          callback?.onMediaMessageSent.call(code, message);
        }
    );
    var result = await XmmImManager.instance.engine
        ?.sendMediaMessage(message, listener: internalCallback);
    return result ?? -1;
  }

  Future<int> removeConversation(String targetId, {
    RCIMIWConversationType? type,
    IRCIMIWRemoveConversationCallback? callback,
  }) async {
    IRCIMIWRemoveConversationCallback? internalCallback =
    IRCIMIWRemoveConversationCallback(
      onConversationRemoved: (int? code) {
        XmmEventBus.instance.emit(XmmAppConst.eventRemoveConversationKey, targetId);
        XmmXLogcat.d("Im onConversationRemoved code: $code targetId: $targetId");
        callback?.onConversationRemoved.call(code);
      },
    );
    var result = await XmmImManager.instance.engine?.removeConversation(
      type ?? RCIMIWConversationType.private,
      targetId,
      null,
      callback: internalCallback,
    );
    XmmXLogcat.d("Im removeConversation result: $result targetId: $targetId");
    return result ?? -1;
  }

  Future<int> clearMessages(String targetId, {
    RCIMIWConversationType? type,
    IRCIMIWClearMessagesCallback? callback,
  }) async {
    IRCIMIWClearMessagesCallback? internalCallback =
    IRCIMIWClearMessagesCallback(
      onMessagesCleared: (int? code) {
        XmmXLogcat.d("Im onMessagesCleared code: $code targetId: $targetId");
        callback?.onMessagesCleared.call(code);
      },
    );
    var result = await XmmImManager.instance.engine?.clearMessages(
      type ?? RCIMIWConversationType.private,
      targetId,
      null,
      0,
      RCIMIWMessageOperationPolicy.localRemote,
      callback: internalCallback,
    );
    XmmXLogcat.d("Im clearMessages result: $result targetId: $targetId");
    return result ?? -1;
  }

  Future<int> clearUnreadCount(String targetId, {
    RCIMIWConversationType? type,
    int? sentTime,
    IRCIMIWClearUnreadCountCallback? callback,
  }) async {
    IRCIMIWClearUnreadCountCallback? callback = IRCIMIWClearUnreadCountCallback(
      onUnreadCountCleared: (int? code) {
        XmmEventBus.instance.emit(
            XmmAppConst.eventClearUnreadCountKey, targetId);
        XmmXLogcat.d("Im clearUnreadCount result: $code code: $targetId sentTime:$sentTime");
      },
    );
    var result = await XmmImManager.instance.engine?.clearUnreadCount(
      type ?? RCIMIWConversationType.private,
      targetId,
      null,
      sentTime ?? DateTime
          .now()
          .millisecondsSinceEpoch,
      callback: callback,
    );
    XmmXLogcat.d("Im clearUnreadCount result: $result targetId: $targetId");
    return result ?? -1;
  }

  void disconnect() {
    XmmXLogcat.d("Im disconnect");
    engine?.disconnect(false);
  }
}
